"""
Command Line Interface for TIR

Provides the main entry point and command-line interface for the
C++ Template Instantiation Revealer tool.
"""

import os
import sys
import time
from pathlib import Path
from typing import Optional, List

import click

from .project_context import ProjectContext
from .ast_parser import ASTParser, SourcePosition
from .type_resolver import TypeResolver
from .formatter import OutputFormatter


class TIRAnalyzer:
    """Main TIR analyzer that coordinates all components."""
    
    def __init__(self, compile_commands_path: Optional[str] = None):
        self.project_context = ProjectContext(compile_commands_path)
        self.ast_parser = ASTParser()
        self.type_resolver = TypeResolver()
        self.formatter = OutputFormatter()
    
    def analyze_symbol_at_position(self,
                                 file_path: str,
                                 line: int,
                                 column: int,
                                 output_format: str = "basic") -> str:
        """Analyze a symbol at the specified position."""
        try:
            # Auto-detect compile_commands.json if not provided
            if not self.project_context.compile_commands_path:
                self.project_context.auto_detect_and_load(file_path)
            
            # Get compilation arguments for the file
            compile_args = self.project_context.get_compile_args_for_file(file_path)
            
            # Parse the file
            start_time = time.time()
            
            if not self.ast_parser.parse_file(file_path, compile_args):
                diagnostics = self.ast_parser.get_diagnostics()
                return self.formatter.format_parse_error(file_path, diagnostics)
            
            parse_time = time.time() - start_time
            
            # Find cursor at position
            position = SourcePosition(file_path, line, column)
            cursor = self.ast_parser.find_cursor_at_position(position)
            
            if not cursor:
                return self.formatter.format_no_symbol_found(f"line {line}, column {column}", position)
            
            # Extract variable name
            variable_name = cursor.spelling or f"<anonymous_at_{line}_{column}>"
            
            # Resolve type
            resolved_type = self.type_resolver.resolve_cursor_type(cursor)
            
            if not resolved_type:
                error_msg = f"Could not resolve type for symbol '{variable_name}'"
                return self.formatter.format_error_output(error_msg, position)
            
            # Get additional context
            context = self.ast_parser.get_cursor_context(cursor)
            context['parse_time_seconds'] = parse_time
            
            # Format output
            if output_format == "json":
                return self.formatter.format_json_output(variable_name, resolved_type, position, context)
            elif output_format == "detailed":
                return self.formatter.format_detailed_output(variable_name, resolved_type, position, context)
            else:  # basic
                return self.formatter.format_basic_output(variable_name, resolved_type, position)
        
        except Exception as e:
            return self.formatter.format_error_output(str(e), SourcePosition(file_path, line, column))
        
        finally:
            # Cleanup
            self.ast_parser.cleanup()
            self.type_resolver.clear_cache()
    
    def analyze_symbol_by_name(self,
                             file_path: str,
                             symbol_name: str,
                             output_format: str = "basic") -> str:
        """Analyze a symbol by name."""
        try:
            # Auto-detect compile_commands.json if not provided
            if not self.project_context.compile_commands_path:
                self.project_context.auto_detect_and_load(file_path)
            
            # Get compilation arguments for the file
            compile_args = self.project_context.get_compile_args_for_file(file_path)
            
            # Parse the file
            start_time = time.time()
            
            if not self.ast_parser.parse_file(file_path, compile_args):
                diagnostics = self.ast_parser.get_diagnostics()
                return self.formatter.format_parse_error(file_path, diagnostics)
            
            parse_time = time.time() - start_time
            
            # Find cursors by name
            cursors = self.ast_parser.find_cursor_by_name(symbol_name)
            
            if not cursors:
                position = SourcePosition(file_path, 0, 0)
                return self.formatter.format_no_symbol_found(f"symbol '{symbol_name}'", position)
            
            # Analyze all found symbols (typically there should be one, but handle multiple)
            results = []
            
            for cursor in cursors:
                # Resolve type
                resolved_type = self.type_resolver.resolve_cursor_type(cursor)
                
                if resolved_type:
                    location = cursor.location
                    position = SourcePosition(
                        file_path,
                        location.line if location else 0,
                        location.column if location else 0
                    )
                    
                    # Get additional context
                    context = self.ast_parser.get_cursor_context(cursor)
                    context['parse_time_seconds'] = parse_time
                    
                    # Format output
                    if output_format == "json":
                        result = self.formatter.format_json_output(symbol_name, resolved_type, position, context)
                    elif output_format == "detailed":
                        result = self.formatter.format_detailed_output(symbol_name, resolved_type, position, context)
                    else:  # basic
                        result = self.formatter.format_basic_output(symbol_name, resolved_type, position)
                    
                    results.append(result)
            
            if not results:
                error_msg = f"Could not resolve type for any instances of symbol '{symbol_name}'"
                return self.formatter.format_error_output(error_msg)
            
            # If multiple results, combine them
            if len(results) == 1:
                return results[0]
            else:
                combined_output = f"Found {len(results)} instances of '{symbol_name}':\n\n"
                combined_output += "\n\n" + "="*60 + "\n\n".join(results)
                return combined_output
        
        except Exception as e:
            return self.formatter.format_error_output(str(e))
        
        finally:
            # Cleanup
            self.ast_parser.cleanup()
            self.type_resolver.clear_cache()


@click.command()
def diagnose():
    """Check libclang configuration and installation status."""
    from .libclang_config import print_libclang_status
    print_libclang_status()


@click.command()
@click.option('-f', '--file', 'file_path', required=True,
              help='Path to the C++ source file to analyze')
@click.option('-l', '--line', type=int,
              help='Line number of the symbol to analyze')
@click.option('-c', '--column', type=int,
              help='Column number of the symbol to analyze')
@click.option('-s', '--symbol', 'symbol_name',
              help='Name of the symbol to analyze (alternative to line/column)')
@click.option('--compile-commands', 'compile_commands_path',
              help='Path to compile_commands.json file')
@click.option('--format', 'output_format',
              type=click.Choice(['basic', 'detailed', 'json']),
              default='basic',
              help='Output format (default: basic)')
@click.option('--verbose', '-v', is_flag=True,
              help='Enable verbose output')
def main(file_path: str,
         line: Optional[int],
         column: Optional[int],
         symbol_name: Optional[str],
         compile_commands_path: Optional[str],
         output_format: str,
         verbose: bool):
    """
    C++ Template Instantiation Revealer (TIR)
    
    Analyze C++ template instantiations and reveal concrete types.
    
    Examples:
    
    \b
        # Analyze symbol at specific location
        tir -f ./src/main.cpp -l 42 -c 10
        
        # Analyze symbol by name  
        tir -f ./src/main.cpp -s my_variable
        
        # Use project compile commands
        tir -f ./src/main.cpp -l 42 -c 10 --compile-commands ./build/compile_commands.json
        
        # Get detailed output with context
        tir -f ./src/main.cpp -l 42 -c 10 --format detailed
        
        # Get JSON output for programmatic use
        tir -f ./src/main.cpp -l 42 -c 10 --format json
    """
    
    # Validate input arguments
    if not (line and column) and not symbol_name:
        click.echo("Error: Must specify either --line and --column, or --symbol", err=True)
        sys.exit(1)
    
    if (line or column) and symbol_name:
        click.echo("Error: Cannot specify both position (--line/--column) and --symbol", err=True)
        sys.exit(1)
    
    if (line and not column) or (column and not line):
        click.echo("Error: Must specify both --line and --column when using position", err=True)
        sys.exit(1)
    
    # Check if file exists
    if not os.path.exists(file_path):
        click.echo(f"Error: File not found: {file_path}", err=True)
        sys.exit(1)
    
    # Check if compile_commands.json exists if specified
    if compile_commands_path and not os.path.exists(compile_commands_path):
        click.echo(f"Error: compile_commands.json not found: {compile_commands_path}", err=True)
        sys.exit(1)
    
    try:
        # Create analyzer
        analyzer = TIRAnalyzer(compile_commands_path)
        
        if verbose:
            click.echo(f"Analyzing file: {file_path}", err=True)
            if compile_commands_path:
                click.echo(f"Using compile commands: {compile_commands_path}", err=True)
        
        # Perform analysis
        if symbol_name:
            result = analyzer.analyze_symbol_by_name(file_path, symbol_name, output_format)
        else:
            result = analyzer.analyze_symbol_at_position(file_path, line, column, output_format)
        
        # Output result
        click.echo(result)
    
    except KeyboardInterrupt:
        click.echo("\nAnalysis interrupted by user", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"Unexpected error: {e}", err=True)
        if verbose:
            import traceback
            traceback.print_exc()
        sys.exit(1)


if __name__ == '__main__':
    main()